/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.femModel.element;

import java.util.ListIterator;

import br.ufmg.dees.insane.materialMedia.degeneration.Degeneration;
import br.ufmg.dees.insane.model.femModel.elementNode.ElementNode;
import br.ufmg.dees.insane.model.femModel.node.Node;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;
import br.ufmg.dees.insane.util.numericalIntegration.IntegrationOrder;
import br.ufmg.dees.insane.util.pointValues.PointValues;

/**
 * A class representing a parametric element.<p>
 * @author  Lucas, Marcelo & Pitangueira, Roque
 * @version  1.0
 * @since  June 2004
 */

public abstract class ParametricElement extends Element 
{
	/** The Integration Order of this Element. */
    protected IntegrationOrder integrationOrder;

	/**Constructs a Parametric Element.*/	
	public ParametricElement(){
	}

	/**
	 * Gets the integration order of this element
	 * @return  Returns the integration order of this element.
	 * @uml.property  name="integrationOrder"
	 */
	public IntegrationOrder getIntegrationOrder() {
	   return this.integrationOrder;
	}
	
	/**
	 * Sets the integration order of this element
	 * @param myIntegrationOrder  The IntegrationOrder to set.
	 * @uml.property  name="integrationOrder"
	 */
	public void setIntegrationOrder(IntegrationOrder io) {
	  this.integrationOrder = io;
	}
	
	/** Init Degenerations, setting the Integration Points and theirs Weights factors of this ParametricElement.*/
	public abstract void initDegenerations();
	  	  
	/**Return the nodal state variable of this Paramentric Element.*/
	public double[] getStateVariables() {
		double[] elmNodeStateVariables = new double[(this.getNumberOfDegreesOfFreedom())];
		ListIterator nodes = incidence.listIterator();
		int j = 0;
		while(nodes.hasNext()) {
			int k = 0;
			ElementNode node = (ElementNode) nodes.next();
			PointValues pv = node.getNodeValues(node.DOF_LABELS);
			for(int i=0; i<pv.getSize(); i++) {
				elmNodeStateVariables[k+j] = node.getNode().getNodeValues(Node.STATE_VARIABLE).getDoublePointValue(i);
				k++;
			}
			j = (j + pv.getSize());
		}
		return(elmNodeStateVariables);
	}
	
	/** Return the Internal Variables in a provided degeneration.
	*@param dg The degeneration.
	*@return The IVector containing the InternalVariables in a provided degeneration
	*/
	public IVector getDegenerationInternalVariables(Degeneration dg) {
		return this.getPointInternalVariables(dg);
	}
	
	/** Return the Dual Internal Variables in a degeneration.
	*@param dg The degeneration.
	*@return The IVector containing the Dual Internal Variables in a material point
	*/
	public IVector getDegenerationDualInternalVariables(Degeneration dg) {
		return dg.mountDualInternalVariableVector(this.getPointInternalVariables(dg));
	}
	
	/** Return the Internal Variables in a provided material point of a degeneration.
	*@param dg The degeneration.
	*@param mplabel The material point label.
	*@return The IVector containing the InternalVariables in a provided material point of a degeneration.
	*/
	public IVector getMPInternalVariables(Degeneration dg, String mplabel) {
		return dg.getMPInternalVariables(mplabel,this.getDegenerationInternalVariables(dg));
	}
	
	/** Return the Dual Internal Variables in a provided material point of a degeneration.
	*@param dg The degeneration.
	*@param mplabel The material point label.
	*@return sigma The IVector containing the DualInternalVariables in a provided material point of a degeneration.
	*/
	public IVector getMPDualInternalVariables(Degeneration dg, String mplabel) {
		return dg.getMPDualInternalVariables(mplabel,this.getMPInternalVariables(dg,mplabel));
	}
	
	/** Return the array containing the DualInternalVariables in all degenerations. 
	*@return mpDualInternalVariables The active stress in all degenerations.
	*/
	public double[][] getDegenerationsDualInternalVariables(){
		Degeneration degeneration;
		double[][] dgDualInternalVariables = new double[degenerations.size()][(analysisModel.getNumberOfDualInternalVariables())];
		ListIterator dgs = degenerations.listIterator();
		int i = 0;
		while(dgs.hasNext()){
		    degeneration = (Degeneration) dgs.next();
			for(int j = 0; j < (analysisModel.getNumberOfDualInternalVariables()); j++){
			    dgDualInternalVariables[i][j] = (double)(this.getDegenerationDualInternalVariables(degeneration)).getElement(j);
			}
			i++;
		}
		return dgDualInternalVariables;
	}
	
	/** Updates all variables of this element based on the nodal variables state.
	*/
	public void update(){
        ListIterator mps = degenerations.listIterator();
        while(mps.hasNext()) {
            Degeneration degeneration = (Degeneration) mps.next();
            degeneration.update();
        }
    }
	
	/** Return the IVector containing the cartesian coordinates of a point.
	*@param point The natural coordinates of the point.
	*@return The IVector containing the cartesian coordinates of a point.
	*/
	public IVector getCartesianPointCoords(double[] point) {
	    IMatrix MatrixN = this.analysisModel.getGeometricOperator(this.Shape.getShapeFunction(point,this.getCartesianNodalCoordsMatrix()));
	    IVector pointCoords = new IVector(MatrixN.getNumRow());
		pointCoords.mul(MatrixN, this.getCartesianNodalCoordsVector());
	    return pointCoords;
	}
	
    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.model.femModel.element.Element#getElmCoefficient()
     */
    public abstract double getElmCoefficient();

    /* (non-Javadoc)
     * @see br.ufmg.dees.insane.model.femModel.element.Element#addDegeneration(br.ufmg.dees.insane.materialMedia.degeneration.Degeneration)
     */
    public abstract void addDegeneration(Degeneration dg);
    
}//end of ParametricElement

